home *** CD-ROM | disk | FTP | other *** search
- /*
- * @(#)writeTree.c 1.6 3/13/89
- */
- #include "assert.h"
- #include "error.h"
- #include "scan.h"
- #include "nodes.h"
- #include "symbols.h"
- #include "MyParser.h"
- #include "semantics.h"
- #include "system.h"
- #include "map.h"
- #include "version.h"
- #include "environment.h"
- #include "flags.h"
- #include <a.out.h>
- #include "builtins.h"
- #include "trace.h"
-
- extern char *ATName();
- extern void myLink();
-
- #define MAXRELOCATIONBLOCKS 400
- #define BLOCKSIZE 1024
- #define RELOCATIONSPERBLOCK (1024 / sizeof(struct relocation_info))
- static char *theOIDFileName;
- static int treeVersion = TREEVERSION;
-
- static struct exec header;
- static struct sts {
- int size;
- char strings[20];
- } *stringTable;
- static int stringTableSize;
- static struct nlist symbolTable;
- typedef struct {
- struct relocation_info rl[RELOCATIONSPERBLOCK];
- } RelocationBlock, *RelocationBlockPtr;
- static RelocationBlockPtr relocationBlocks[MAXRELOCATIONBLOCKS];
- static int nextRelocationBlockIndex;
- static RelocationBlockPtr rbp;
- static struct relocation_info *rp, *rpe;
- static int nextOffset;
- static FILE *fp;
- static Map offsetMap, CTMap;
-
- static int Pass;
-
- static void _DoAReference(), writeInt(), Pass1(), Pass2(), writeBody();
- #define OFFSETOF(fNode) Map_Lookup(offsetMap, (int) fNode)
- #define SETOFFSET(fNode, value) Map_Insert(offsetMap, (int)fNode, (int)value)
- static int getOffset();
-
- static NodePtr theRoot, aGlobalRef;
-
- /*
- * When we write out the file, we write out all the tree nodes. Global
- * references are changed to remove the "cache". Builtin object references
- * are left alone. We then write out the modified symbol table and ident
- * table entries.
- */
-
- static void squirrelSymbol(p)
- NodePtr p;
- {
- register Symbol st = p->b.symdef.symbol;
- int filePosition, rightFilePosition;
- int thisSymbolOffset;
-
- st = ST_Fetch(st);
- if (OFFSETOF(st) == NIL) {
- assert(Pass == 1);
- thisSymbolOffset = nextOffset;
- SETOFFSET(st, thisSymbolOffset);
- nextOffset += 2 + 2 + 1 + 1 + 1 + 1; /* up to value */
- if ((int)st->value.ATinfo > 0x200) _DoAReference(nextOffset);
- nextOffset += sizeof(NodePtr);
- if ((int)st->value.CTinfo > 0x200) _DoAReference(nextOffset);
- nextOffset += sizeof(NodePtr);
- if ((int)st->value.value > 0x200) _DoAReference(nextOffset);
- nextOffset += sizeof(NodePtr);
- nextOffset += sizeof(Address);
- if (st->itsName != NULL) _DoAReference(nextOffset);
- nextOffset += sizeof(char *);
- if (st->itsName != NULL) nextOffset += ((strlen(st->itsName)+1+3) & ~0x3);
- Pass1(st->value.ATinfo, FALSE);
- if ((int) st->value.CTinfo > 0x200) Map_Insert(CTMap, (int)st->value.CTinfo, 1);
- Pass1(st->value.value, FALSE);
- }
- if (Pass == 2) {
- /* write the tree node */
- filePosition = ftell(fp);
- rightFilePosition = getOffset(p) + sizeof(struct exec);
- assert (filePosition == rightFilePosition);
- writeBody(p, 1);
- writeInt(getOffset((NodePtr)p->b.symdef.symbol));
- /* now check for the symbol itself */
- thisSymbolOffset = OFFSETOF(st);
- if (thisSymbolOffset < 0) return;
- SETOFFSET(st, -thisSymbolOffset);
- filePosition = ftell(fp);
- rightFilePosition = thisSymbolOffset + sizeof(struct exec);
- assert (filePosition == rightFilePosition);
- if (fwrite((char *)st, 8, 1, fp) != 1) assert(FALSE);
- writeInt(getOffset(st->value.ATinfo));
- writeInt(getOffset(st->value.CTinfo));
- writeInt(getOffset(st->value.value ));
- if (fwrite((char *)&st->v.address, sizeof(Address), 1, fp) != 1) assert(FALSE);
- writeInt(thisSymbolOffset + sizeof(STEntry));
- filePosition = ftell(fp);
- rightFilePosition += sizeof(STEntry);
- assert(filePosition == rightFilePosition);
- if (st->itsName != NULL) {
- register int i, strLength;
- i = strlen(st->itsName);
- strLength = (i+1+3) & ~0x3;
- if (fwrite(st->itsName, 1, i, fp) != i) assert(FALSE);
- for (; i < strLength; i++) (void) fputc('\0', fp);
- }
- Pass2(st->value.ATinfo, FALSE);
- Pass2(st->value.value, FALSE);
- }
- }
-
- /*
- * This one needs to initialize the header, and initialize the mapping
- * structures.
- */
-
- static void initializeOutput(treeName)
- char *treeName;
- {
- #ifdef sun
- header.a_dynamic = 0;
- header.a_machtype = M_68020;
- #endif
- header.a_magic = 0407;
- header.a_text = 0;
- header.a_bss = 0;
- header.a_syms = 1 * sizeof(struct nlist);
- symbolTable.n_un.n_strx = 4;
- symbolTable.n_type = N_DATA;
- if (*treeName == '_') symbolTable.n_type |= N_EXT;
- symbolTable.n_other = 0;
- symbolTable.n_desc = 0;
- symbolTable.n_value = 12;
- stringTableSize = (strlen(treeName) + 1 + 3) & ~0x3;
- stringTableSize += 4;
- stringTable = (struct sts *) calloc((unsigned)stringTableSize, 1);
- stringTable->size = stringTableSize;
- (void) strcpy(stringTable->strings, treeName);
- header.a_entry = 0;
- header.a_trsize = 0;
- nextRelocationBlockIndex = 0;
- rbp = (RelocationBlockPtr) calloc(sizeof (RelocationBlock), 1);
- relocationBlocks[nextRelocationBlockIndex++] = rbp;
- rp = &rbp->rl[0];
- rpe = &rp[RELOCATIONSPERBLOCK];
- nextOffset = 12;
- /*
- * Leaves header.a_data and header.a_drsize undone.
- */
- offsetMap = Map_Create();
- CTMap = Map_Create();
- Pass = 1;
- }
-
- static void Pass1CTs()
- {
- NodePtr ct;
- int value;
- Map_For(CTMap, ct, value)
- assert(value == 1);
- if (ct->tag == P_OBLIT && ct->b.oblit.f.dependsOnTypeVariable) {
- /* do nothing */
- } else {
- if (OFFSETOF(ct) == NIL) {
- /* we have not done this one already */
- Pass1(ct, TRUE);
- }
- }
- Map_Next
- }
-
- static void Pass2CTs()
- {
- NodePtr ct;
- int value;
- Map_For(CTMap, ct, value)
- assert(value == 1);
- if (ct->tag == P_OBLIT && ct->b.oblit.f.dependsOnTypeVariable) {
- /* do nothing */
- } else {
- if (OFFSETOF(ct) >= 0) {
- /* we have not done this one already */
- Pass2(ct, TRUE);
- }
- }
- Map_Next
- }
-
- static void intermediate()
- {
- int i;
- header.a_data = nextOffset;
- header.a_drsize = (nextRelocationBlockIndex - 1) * BLOCKSIZE +
- (int) rp - (int) rbp;
- if (fwrite((char *)&header, sizeof(header), 1, fp) != 1) assert(FALSE);
- /* We write the tree Version number here. We also need to make
- the offsets all non zero. */
- i = TREEMAGIC;
- if (fwrite((char *)&i, sizeof(int), 1, fp) != 1) assert(FALSE);
- if (fwrite((char *)&treeVersion, sizeof(int), 1, fp) != 1) assert(FALSE);
- if (fwrite((char *)&nextOffset, sizeof(int), 1, fp) != 1) assert(FALSE);
- Pass = 2;
- }
-
- static void finalize()
- {
- int filePosition, rightFilePosition;
- register int i;
- filePosition = ftell(fp);
- rightFilePosition = sizeof(struct exec) + header.a_data;
- assert (filePosition == rightFilePosition);
- for (i = 0; i < nextRelocationBlockIndex - 1; i++) {
- if (fwrite((char *)relocationBlocks[i], BLOCKSIZE, 1, fp) != 1) assert(FALSE);
- free((char *)relocationBlocks[i]);
- }
- i = (int) rp - (int) &rbp->rl[0];
- if (i != 0) if (fwrite((char *)rbp, i, 1, fp) != 1) assert(FALSE);
- free((char *)rbp);
- if (fwrite((char *)&symbolTable, sizeof(symbolTable), 1, fp) != 1) assert(FALSE);
- if (fwrite((char *)stringTable, stringTableSize, 1, fp) != 1) assert(FALSE);
- free((char *)stringTable);
- Map_Destroy(offsetMap);
- Map_Destroy(CTMap);
- }
-
- #define DOAREFERENCE(fNode, fE) \
- if ((int) (fE) > 0x200) \
- _DoAReference(thisNodeOffset + (int)(&(fE))-(int)fNode)
-
- static void _DoAReference(offset)
- int offset;
- {
- register struct relocation_info *myrp;
- if (rp >= rpe) {
- if (nextRelocationBlockIndex >= MAXRELOCATIONBLOCKS) {
- fprintf(stderr, "Out of relocation blocks (allocated %d)\n",
- MAXRELOCATIONBLOCKS * RELOCATIONSPERBLOCK);
- exit(1);
- }
- rbp = (RelocationBlockPtr) calloc(sizeof (RelocationBlock), 1);
- relocationBlocks[nextRelocationBlockIndex++] = rbp;
- rp = &rbp->rl[0];
- rpe = &rp[RELOCATIONSPERBLOCK];
- }
- myrp = rp++;
- myrp->r_address = offset;
- myrp->r_symbolnum = N_DATA;
- myrp->r_pcrel = 0;
- myrp->r_length = 2;
- myrp->r_extern = 0;
- }
-
- static Boolean doneFirstNode;
-
- static Boolean OBLitShouldBeSeparate(p)
- NodePtr p;
- {
- if (p != theRoot && p->b.oblit.f.writeSeparately) return(TRUE);
- if (!bflag && p->tag == P_OBLIT && p->b.oblit.f.inExecutableConstruct &&
- (EnvironmentStage)Map_Lookup(environmentMap, (int)p->b.oblit.codeOID) == E_Imported)
- return(TRUE);
- return(FALSE);
- }
-
- static void scheduleOBLitOutput(p, id)
- NodePtr p;
- OID id;
- {
- if (bflag) {
- if (((id & 0xff000000) == (OID) 0xff000000) &&
- ((id & 0x1f) == (theRoot->b.oblit.id & 0x1f))) {
- scheduleOutput(id);
- } else if ((id & 0xffffff00) != (OID)0xff000000) {
- TRACE2(builtins, 1, "Writing tree for non-builtin %s with id 0x%08x", ATName(p), id);
- scheduleOutput(id);
- } else {
- TRACE2(builtins, 1, "Not writing tree for %s with id 0x%08x", ATName(p), id);
- }
- } else {
- scheduleOutput(id);
- }
- }
-
- static void Pass1(fNode, isCT)
- register NodePtr fNode;
- Boolean isCT;
- {
- register int i;
- int thisNodeOffset;
- Boolean done = FALSE;
- Symbol st;
- NodePtr saveAT;
-
- if ((int)fNode <= 0x200) {
- /* don't worry about these. */
- } else if (fNode == theRoot && doneFirstNode) {
- nextOffset += UsedNodeSize(aGlobalRef);
- } else if (OFFSETOF(fNode) != NIL) {
- /* We've done this one already */
- } else {
- doneFirstNode = TRUE;
- thisNodeOffset = nextOffset;
- SETOFFSET(fNode, thisNodeOffset);
- nextOffset += UsedNodeSize(fNode);
- switch (fNode->tag) {
- case P_GLOBALREF:
- done = TRUE;
- break;
- case P_OPNAME:
- done = TRUE;
- break;
- case P_ATLIT:
- assert(!isCT);
- if (OBLitShouldBeSeparate(fNode)) {
- /*
- * We have a pointer to a manifest atlit. We need to write out a
- * globalref node.
- */
- nextOffset -= UsedNodeSize(fNode);
- nextOffset += UsedNodeSize(aGlobalRef);
- done = TRUE;
- }
- break;
- case P_OBLIT:
- if (isCT || OBLitShouldBeSeparate(fNode)) {
- /*
- * We have a pointer to a manifest oblit. We need to write out a
- * globalref node.
- */
- nextOffset -= UsedNodeSize(fNode);
- nextOffset += UsedNodeSize(aGlobalRef);
- done = TRUE;
- } else {
- if (fNode->b.oblit.f.isTypeVariable) {
- saveAT = fNode->b.oblit.myat;
- fNode->b.oblit.myat = NULL;
- }
- st = ST_Fetch(fNode->b.oblit.name->b.symdef.symbol);
- st->value.ATinfo = fNode->b.oblit.myat;
- for (i = fNode->firstChild; i < fNode->nChildren; i++) {
- DOAREFERENCE(fNode, fNode->b.children[i]);
- Pass1(fNode->b.children[i], FALSE);
- }
- if (fNode->b.oblit.f.isTypeVariable) {
- fNode->b.oblit.myat = saveAT;
- st = ST_Fetch(fNode->b.oblit.name->b.symdef.symbol);
- st->value.ATinfo = saveAT;
- }
- done = TRUE;
- }
- break;
- case T_IDENT:
- done = TRUE;
- break;
- case T_STRING:
- case P_CHARLIT:
- case P_INTLIT:
- case P_REALLIT:
- case P_STRINGLIT:
- /* We write the string */
- DOAREFERENCE(fNode, fNode->b.string.string);
- nextOffset += ((strlen(fNode->b.string.string)+1+3) & ~0x3);
- done = TRUE;
- break;
- case P_BOOLLIT:
- done = TRUE;
- break;
- case P_BUILTINLIT:
- done = TRUE;
- break;
- case P_PARAM:
- case P_ARG:
- break;
- case P_SYMREF:
- case P_SYMDEF:
- DOAREFERENCE(fNode, fNode->b.symdef.symbol);
- squirrelSymbol(fNode);
- done = TRUE;
- break;
- case P_FIELDREF:
- assert(FALSE);
- break;
- case P_OPSIG:
- break;
- case P_COMP:
- case P_IMPORT:
- assert(FALSE);
- break;
- case P_EXPORT:
- break;
- case P_RECORDLIT:
- case P_UNIONLIT:
- case P_ENUMLIT:
- assert(FALSE);
- break;
- case P_CONSTDECL:
- case P_VARDECL:
- case P_VECTORLIT:
- case P_PRAGMA:
- case P_MONITOR:
- case P_OPDEF:
- case P_PROCESSDEF:
- case P_INITDEF:
- case P_RECOVERYDEF:
- case P_BLOCK:
- case P_UNAVAILABLEHANDLER:
- case P_FAILUREHANDLER:
- case P_IFSTAT:
- case P_IFCLAUSE:
- case P_ELSECLAUSE:
- case P_LOOPSTAT:
- case P_EXITSTAT:
- case P_ASSIGNSTAT:
- case P_ASSERTSTAT:
- case P_FIXSTAT:
- case P_REFIXSTAT:
- case P_UNFIXSTAT:
- case P_MOVESTAT:
- case P_VIEW:
- case P_EXP:
- case P_INVOC:
- break;
- case P_FIELDSEL:
- case P_NTHRESULT:
- case P_KNOWCT:
- case P_KNOWLOCAL:
- case P_KNOWMANIFEST:
- case P_SUBSCRIPT:
- case P_SELECTION:
- assert(FALSE);
- break;
- case P_WHEREWIDGIT:
- case P_PRIMSTAT:
- case P_WAITSTAT:
- case P_SIGNALSTAT:
- case P_UNARYEXP:
- case P_RESTRICT:
- case P_SETQ:
- break;
- default:
- break;
- }
- if (!done) for (i = fNode->firstChild; i < fNode->nChildren; i++) {
- DOAREFERENCE(fNode, fNode->b.children[i]);
- Pass1(fNode->b.children[i], FALSE);
- }
- }
- }
-
- #define IABS(N) ((N) < 0 ? -(N) : (N))
-
- static int getOffset(fNode)
- register NodePtr fNode;
- {
- register int i;
- if ((int) fNode <= 0x200) return ((int) fNode);
- else {
- i = OFFSETOF(fNode);
- return (IABS(i));
- }
- }
-
- static void writeInt(n)
- int n;
- {
- if (fwrite((char *) &n, sizeof(int), 1, fp) != 1) assert(FALSE);
- }
-
- static void writeBody(fNode, n)
- register NodePtr fNode;
- int n;
- {
- if (fwrite((char *)fNode, (2+n)*sizeof(int), 1, fp) != 1) assert(FALSE);
- }
-
- static OID transOID(id)
- OID id;
- {
- register OID result;
- result = (OID) Map_Lookup(translateOIDMap, (int)id);
- return (result == NIL ? id : result);
- }
-
- static void Pass2(fNode, isCT)
- register NodePtr fNode;
- Boolean isCT;
- {
- register int i;
- Boolean done = FALSE;
- int strLength;
- int filePosition, rightFilePosition;
-
- if ((int)fNode <= 0x200) {
- /* don't worry about these. */
- } else if (fNode == theRoot && doneFirstNode) {
- aGlobalRef->b.globalref.id = fNode->b.atlit.id;
- writeBody(aGlobalRef, 2);
- } else if (OFFSETOF(fNode) < 0) {
- /* We've written this one already */
- } else {
- doneFirstNode = TRUE;
- filePosition = ftell(fp);
- rightFilePosition = OFFSETOF(fNode) + sizeof(struct exec);
- assert (filePosition == rightFilePosition);
- SETOFFSET(fNode, -OFFSETOF(fNode));
- switch (fNode->tag) {
- case P_GLOBALREF:
- if (bflag)
- fNode->b.globalref.id = transOID(fNode->b.globalref.id);
- writeBody(fNode, 1);
- writeInt(0);
- done = TRUE;
- break;
- case P_OPNAME:
- writeBody(fNode, 2);
- done = TRUE;
- break;
- case P_ATLIT:
- assert(!isCT);
- if (OBLitShouldBeSeparate(fNode)) {
- /*
- * We have a pointer to a manifest atlit. We need to write out a
- * globalref node.
- */
- aGlobalRef->b.globalref.id = fNode->b.atlit.id;
- if (bflag)
- aGlobalRef->b.globalref.id = transOID(aGlobalRef->b.globalref.id);
- writeBody(aGlobalRef, 2);
- if (!isCT) scheduleOBLitOutput(fNode, aGlobalRef->b.globalref.id);
- done = TRUE;
- }
- break;
- case P_OBLIT:
- if (isCT || OBLitShouldBeSeparate(fNode)) {
- /*
- * We have a pointer to a manifest oblit. We need to write out a
- * globalref node.
- */
- if (isCT) {
- assert(fNode->b.oblit.codeOID != 0);
- aGlobalRef->b.globalref.id = fNode->b.oblit.codeOID;
- } else {
- aGlobalRef->b.globalref.id =
- fNode->b.oblit.id ? fNode->b.oblit.id : fNode->b.oblit.codeOID;
- }
- if (bflag)
- aGlobalRef->b.globalref.id = transOID(aGlobalRef->b.globalref.id);
- writeBody(aGlobalRef, 2);
- if (!isCT) scheduleOBLitOutput(fNode, aGlobalRef->b.globalref.id);
- done = TRUE;
- } else {
- if (!bflag && fNode->b.oblit.codeOID != 0) {
- char *theSecondOIDFileName;
- theSecondOIDFileName = makeOIDFileName(fNode->b.oblit.codeOID);
- myLink(theOIDFileName, theSecondOIDFileName, TRUE, fNode);
- TRACE2(environment, 5, "Linking %s to %s", theSecondOIDFileName,
- theOIDFileName);
- }
- }
- break;
- case T_IDENT:
- break;
- case T_STRING:
- case P_CHARLIT:
- case P_INTLIT:
- case P_REALLIT:
- case P_STRINGLIT:
- /* We write the string */
- writeBody(fNode, 0);
- writeInt((int)(-OFFSETOF(fNode) + BODYSIZE + 4));
- strLength = (strlen(fNode->b.string.string)+1+3) & ~0x3;
- i = strlen(fNode->b.string.string);
- if (fwrite(fNode->b.string.string, 1, i, fp) != i) assert(FALSE);
- for (; i < strLength; i++) (void) fputc('\0', fp);
- done = TRUE;
- break;
- case P_BOOLLIT:
- break;
- case P_BUILTINLIT:
- break;
- case P_PARAM:
- case P_ARG:
- break;
- case P_SYMREF:
- case P_SYMDEF:
- squirrelSymbol(fNode);
- done = TRUE;
- break;
- case P_FIELDREF:
- assert(FALSE);
- break;
- case P_OPSIG:
- break;
- case P_COMP:
- case P_IMPORT:
- assert(FALSE);
- break;
- case P_EXPORT:
- break;
- case P_RECORDLIT:
- case P_UNIONLIT:
- case P_ENUMLIT:
- assert(FALSE);
- break;
- case P_CONSTDECL:
- case P_VARDECL:
- case P_VECTORLIT:
- case P_PRAGMA:
- case P_MONITOR:
- case P_OPDEF:
- case P_PROCESSDEF:
- case P_INITDEF:
- case P_RECOVERYDEF:
- case P_BLOCK:
- case P_UNAVAILABLEHANDLER:
- case P_FAILUREHANDLER:
- case P_IFSTAT:
- case P_IFCLAUSE:
- case P_ELSECLAUSE:
- case P_LOOPSTAT:
- case P_EXITSTAT:
- case P_ASSIGNSTAT:
- case P_ASSERTSTAT:
- case P_FIXSTAT:
- case P_REFIXSTAT:
- case P_UNFIXSTAT:
- case P_MOVESTAT:
- case P_VIEW:
- case P_EXP:
- case P_INVOC:
- break;
- case P_FIELDSEL:
- case P_NTHRESULT:
- case P_KNOWCT:
- case P_KNOWLOCAL:
- case P_KNOWMANIFEST:
- case P_SUBSCRIPT:
- case P_SELECTION:
- assert(FALSE);
- break;
- case P_WHEREWIDGIT:
- case P_PRIMSTAT:
- case P_WAITSTAT:
- case P_SIGNALSTAT:
- case P_UNARYEXP:
- case P_RESTRICT:
- case P_SETQ:
- break;
- default:
- break;
- }
- if (!done) {
- writeBody(fNode, fNode->firstChild);
- for (i = fNode->firstChild; i < fNode->nChildren; i++) {
- writeInt(getOffset(fNode->b.children[i]));
- }
- for (i = fNode->firstChild; i < fNode->nChildren; i++) {
- Pass2(fNode->b.children[i], FALSE);
- }
- }
- }
- }
-
- void writeTree(fileName, p)
- char *fileName;
- NodePtr p;
- {
- char *treeName;
- NodePtr symdef;
-
- if (BODYSIZE != 8) assert(FALSE);
- aGlobalRef = Construct(P_GLOBALREF, 0);
- fp = fopen(fileName, "w");
- theOIDFileName = fileName;
- assert (fp != NULL);
- p = GETVALUE(p);
- symdef = p->tag == P_OBLIT ? p->b.oblit.name : p->b.atlit.name;
- if (symdef == NULL) treeName = "unknown";
- else treeName = ST_Fetch(symdef->b.symdef.symbol)->itsName;
- if (!bflag || (p->b.oblit.id & 0xffffff) > (OID)0x000100) {
- treeName = malloc(20);
- sprintf(treeName, "OID%08x", p->b.oblit.id);
- }
- initializeOutput(treeName);
- theRoot = p;
- doneFirstNode = FALSE;
- Pass1(p, FALSE);
- Pass1CTs();
- intermediate();
- doneFirstNode = FALSE;
- Pass2(p, FALSE); /* writes the data */
- Pass2CTs();
- finalize(); /* relocation and symtab */
- if (fclose(fp) == EOF) assert(FALSE);
- fp = NULL;
- }
-